package bjtu.tjj.simpledy.controller.interceptor;

import bjtu.tjj.simpledy.common.ResultCode;
import bjtu.tjj.simpledy.common.keys.RedisKey;
import bjtu.tjj.simpledy.exception.CommonException;
import bjtu.tjj.simpledy.utils.ThreadLocalUtils;
import jakarta.annotation.Nonnull;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
@RequiredArgsConstructor
public class LoginInterceptor implements HandlerInterceptor {
    private final static String TOKEN = "token";
    private final static String OPTIONS = "OPTIONS";
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean preHandle(@Nonnull HttpServletRequest request,
                             @Nonnull HttpServletResponse response,
                             @Nonnull Object handler) {
        if (OPTIONS.equals(request.getMethod())) {
            return true;
        }

        String token = request.getHeader(TOKEN);
        if (token == null) {
            throw new CommonException(ResultCode.NOT_LOGIN);
        }
        String token2UidKey = RedisKey.TOKEN_TO_UID + token;
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        Long userId = (Long) ops.get(token2UidKey);
        if (userId == null || !token.equals(ops.get(RedisKey.UID_TO_TOKEN + userId))) {
            redisTemplate.delete(token2UidKey);
            throw new CommonException(ResultCode.LOGIN_EXPIRES);
        }
        ThreadLocalUtils.set(token, userId);
        return true;
    }

    @Override
    public void afterCompletion(@Nonnull HttpServletRequest request,
                                @Nonnull HttpServletResponse response,
                                @Nonnull Object handler,
                                @Nullable Exception ex) {
        ThreadLocalUtils.remove();
    }
}
